package com.scs.application.modules.sys.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.scs.application.core.consts.Const;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.query.QueryContextHolder;
import com.scs.application.core.service.IBaseFileService;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.svn.SVNHelper;
import com.scs.application.modules.svn.dto.SVNLockInfo;
import com.scs.application.modules.svn.enums.SVNFileLockStatus;
import com.scs.application.modules.sys.dto.DataViewDTO;
import com.scs.application.modules.sys.entity.DataView;
import com.scs.application.modules.sys.service.DataViewService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.wc.*;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

@Slf4j
@Service
@Configuration
public class DataViewServiceImpl implements DataViewService , IBaseFileService<DataView, DataViewDTO> {

    public static Map<String, SVNLockInfo> svnLockInfoMap = new HashMap<String, SVNLockInfo>();

    /**
     * 从JSON文件中获取视图信息
     *
     * @return
     */
    @Override
    public List<DataViewDTO> getDataViewList() {
        List<DataViewDTO> dataViews =  getDTOList(Const.getDataViewDtlSrc());

        QueryContext queryContext = QueryContextHolder.currentContext();
        String viewKey = (String) queryContext.getParams().get("viewKey");
        List<String> svnLockStatus = (List<String>)(queryContext.getParams().get("svnLockStatus"));
        List<String> viewTypes = (List<String>)queryContext.getParams().get("viewType");
        if (StringUtils.isBlank(viewKey) && svnLockStatus == null && viewTypes == null) {
            return dataViews.stream().sorted(Comparator.comparing(DataViewDTO::getViewName)).collect(Collectors.toList());
        }

        if (StringUtils.isNotBlank(viewKey)) {
            if (svnLockStatus != null && svnLockStatus.size() > 0 && viewTypes != null && viewTypes.size() > 0) {
                dataViews = dataViews.stream().filter(dv -> dv.getViewKey().equalsIgnoreCase(viewKey) && svnLockStatus.indexOf(dv.getSvnLockStatus()) > -1 && viewTypes.indexOf(dv.getViewType()) > -1).collect(Collectors.toList());
            } else if (svnLockStatus != null && svnLockStatus.size() > 0) {
                dataViews = dataViews.stream().filter(dv -> dv.getViewKey().equalsIgnoreCase(viewKey) && svnLockStatus.indexOf(dv.getSvnLockStatus()) > -1).collect(Collectors.toList());
            } else if (viewTypes != null && viewTypes.size() > 0) {
                dataViews = dataViews.stream().filter(dv -> dv.getViewKey().equalsIgnoreCase(viewKey) && viewTypes.indexOf(dv.getViewType()) > -1).collect(Collectors.toList());
            }
        } else {
            if (svnLockStatus != null && svnLockStatus.size() > 0 && viewTypes != null && viewTypes.size() > 0) {
                dataViews = dataViews.stream().filter(dv -> svnLockStatus.indexOf(dv.getSvnLockStatus()) > -1 && viewTypes.indexOf(dv.getViewType()) > -1).collect(Collectors.toList());
            } else if (svnLockStatus != null && svnLockStatus.size() > 0) {
                dataViews = dataViews.stream().filter(dv -> svnLockStatus.indexOf(dv.getSvnLockStatus()) > -1).collect(Collectors.toList());
            } else if (viewTypes != null && viewTypes.size() > 0) {
                dataViews = dataViews.stream().filter(dv -> viewTypes.indexOf(dv.getViewType()) > -1).collect(Collectors.toList());
            }
        }

        if (dataViews != null && dataViews.size() > 0)
            return dataViews.stream().sorted(Comparator.comparing(DataViewDTO::getViewName)).collect(Collectors.toList());
        return dataViews;
    }


    @Override
    public DataViewDTO getDTO(String fileSrc) {
        DataViewDTO dataViewDTO = new DataViewDTO();
        String fileName = fileSrc.substring(fileSrc.lastIndexOf('/') + 1);
        String viewKey = fileName.substring(0, fileName.length() - 5);
        dataViewDTO.setViewKey(viewKey);
        if (svnLockInfoMap.containsKey(viewKey) && svnLockInfoMap.get(viewKey) != null && svnLockInfoMap.get(viewKey).getLockStatus() != null) {
            dataViewDTO.setSvnLockStatus(svnLockInfoMap.get(viewKey).getLockStatus().name());
            dataViewDTO.setSvnUserName(svnLockInfoMap.get(viewKey).getUserName());
            dataViewDTO.setSvnStation(svnLockInfoMap.get(viewKey).getStation());
        }
        setDataViewInfo(dataViewDTO, fileSrc);

        return dataViewDTO;
    }

    private void setDataViewInfo(DataViewDTO dataView, String fileNameWithPath) {
//        String dataViewString = FileUtils.readFile(fileNameWithPath);
        String dataViewString = FileUtils.readFileStore(fileNameWithPath);
        if (StringUtils.isEmpty(dataViewString)) {
            return;
        }
        JSONObject jsonObject = JSONObject.parseObject(dataViewString);
        dataView.setViewName(jsonObject.getString("viewName"));
        dataView.setModuleName(jsonObject.getString("moduleName"));
        dataView.setDescription(jsonObject.getString("description"));
        dataView.setCreator(jsonObject.getString("creator"));
        dataView.setTimeCreated(jsonObject.getString("timeCreated"));
        dataView.setModifier(jsonObject.getString("modifier"));
        dataView.setTimeModified(jsonObject.getString("timeModified"));
        dataView.setViewType(jsonObject.getString("viewType"));
        dataView.setColumns(jsonObject.getString("columns"));
    }

    @Override
    public Boolean deleteView(String viewKey) {
        FileUtils.deleteFile(Const.DATA_VIEW_DTL_SRC + viewKey + ".json");
        CacheUtils.remove(CacheUtils.DATAVIEW_CACHE,viewKey);
        return true;
    }

    @Override
    public JSONObject saveView(JSONObject dataView) {
        BusinessException.throwErrorIf(true,"此方法已废弃");
        String viewString="";
        JSONObject jsonObject = JSONObject.parseObject(viewString);
        String viewKey = jsonObject.getString("viewKey");
        String fileNameWithPath = Const.DATA_VIEW_DTL_SRC + viewKey + ".json";
        String editStatus = jsonObject.getString("editStatus");

        // 准备好的写入数据
        String modifier = Tools.getHostName();
        String timeModified = DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");

        if (editStatus.equalsIgnoreCase("addnew")) {
            // 新增的化要检查viewKey的唯一性
            if (new File(fileNameWithPath).exists()) {
                throw new BusinessException("viewKey已经存在，请重新命名！");
            }
            jsonObject.put("creator", modifier);
            jsonObject.put("timeCreated", timeModified);
            svnLockInfoMap.put(viewKey, new SVNLockInfo(SVNFileLockStatus.DRAFT));
        } else {
            jsonObject.put("modifier", modifier);
            jsonObject.put("timeModified", timeModified);

            String dataViewString = getView(viewKey);
/*
            //不更新  xid
            if (StringUtils.isNotBlank(dataViewString)) {
                JSONObject jsonDataViewOld = JSONObject.parseObject(dataViewString);
                if (jsonDataViewOld != null && jsonObject.containsKey("baseColumns")) {
                    JSONArray baseColumnsNew = jsonObject.getJSONArray("baseColumns");
                    if (jsonDataViewOld.containsKey("baseColumns")) {
                        JSONArray baseColumnsOld = jsonDataViewOld.getJSONArray("baseColumns"),findArrList;
                        List findList;
                        for(int i=0 ; i< baseColumnsNew.size() ; i++){
                            JSONObject baseColumnNew = baseColumnsNew.getJSONObject(i);
                            findList = baseColumnsOld.stream().filter(baseColumnTMp -> ((JSONObject)baseColumnTMp).getString("name").equals(baseColumnNew.getString("name"))).collect(Collectors.toList());
                            if (findList == null || findList.size() < 1) continue;

                            findArrList = JSONArray.parseArray(JSON.toJSONString(findList));

                            if (findArrList == null || findArrList.size() < 1) continue;
                            if (findArrList.size() > 1) {
                                throw new BusinessException("保存失败,baseColumns字段重复【%s】",baseColumnNew.getString("name"));
                            }
                            if ("matrName".equals(baseColumnNew.getString("name"))) {
                                log.info("111");
                            }
                            if (findArrList.getJSONObject(0).containsKey("_XID")) {
                                baseColumnsNew.getJSONObject(i).put("_XID", findArrList.getJSONObject(0).getString("_XID"));
                            }else {
                                baseColumnsNew.getJSONObject(i).remove("_XID");
                            }
                        }
                        jsonObject.put("baseColumns",baseColumnsNew);
                    }
                }
            }*/
        }
        String result = JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat);
        FileUtils.writeTxtFile(fileNameWithPath, result);
        CommonService.cacheDataview(viewKey);
        return null;
    }

    @Override
    public String listWithSvnLock() {
        int numAll = 0;
        final int[] numSuccess = {0};
        int numError = 0;
        String protocol = this.getClass().getClassLoader().getResource("").getProtocol();
        SVNRepositoryFactoryImpl.setup();
        SVNStatusClient svnStatusClient = SVNClientManager.newInstance().getStatusClient();

        log.info("#########DataViewServiceImpl.listWithSvnLock 获取数据视图SVN状态开始#########");
        if (!protocol.startsWith("jar")) { //非Jar包启动
            // 文件方式启动
            File path = new File(Const.DATA_VIEW_DTL_SRC);
            File[] files = path.listFiles();
            numAll = files.length;
            //排除掉system_dv_define.json
            numAll--;
            long beginTime = System.currentTimeMillis();

            SVNDepth svnDepth = SVNDepth.getInfinityOrFilesDepth(false);
            SVNRevision svnRevision = SVNRevision.create(new Date());
            try {
                svnStatusClient.doStatus(path, svnRevision, svnDepth, true, true, false, false, new ISVNStatusHandler() {
                    @SneakyThrows
                    @Override
                    public void handleStatus(SVNStatus svnStatus) throws SVNException {
                        if (!"system_dv_define.json".equalsIgnoreCase(svnStatus.getFile().getName())) {
                            String viewKey = svnStatus.getFile().getName().substring(0, svnStatus.getFile().getName().length() - 5);
                            if (svnLockInfoMap.containsKey(viewKey)) svnLockInfoMap.remove(viewKey);
                            SVNLockInfo svnLockInfo = SVNHelper.getLockInfoBySVNStatus(svnStatus);
                            svnLockInfoMap.put(viewKey, svnLockInfo);
                            numSuccess[0]++;
                        }
                    }
                }, null);

                long endTime = System.currentTimeMillis();
                log.info("#########DataViewServiceImpl.listWithSvnLock 获取数据视图SVN状态成功，视图状态更新数量：{},耗时：{} #########", numSuccess[0], DateUtils.formatTime(endTime - beginTime));
            } catch (SVNException e) {
                log.error("#########DataViewServiceImpl.listWithSvnLock 获取数据视图SVN状态失败 #########", e);
            }

        } else {
            log.info("#########DataViewServiceImpl.listWithSvnLock 获取数据视图SVN状态，目前不支持jar包启动方式 #########");
        }
        return "更新完成，总数量：" + numAll + "，成功数量：" + numSuccess[0] + "，失败数量：" + numError;
    }

    @Override
    public String getView(String viewKey) {
        return FileUtils.readFileStore(Const.getDataViewDtlSrc() + viewKey + ".json");
    }

    @Override
    public List<String> getDataviewViewKeyList() {
        String protocol = this.getClass().getClassLoader().getResource("").getProtocol();
        List<String> viewKeyList = new ArrayList<>();

        if (protocol.startsWith("jar")) {
            // jar包方式启动
            log.info("getDataviewViewKeyList.jar 包启动");
            JarFile localJarFile = null;
            try {

                String dataViewDtlSrc = Const.getDataViewDtlSrc();

                String path = this.getClass().getClassLoader().getResource("static/file-store/" + dataViewDtlSrc).getPath();
                path = path.substring("file:\\".length());
                log.info("getDataviewViewKeyList.path = {}",path);
                log.error("getDataviewViewKeyList.path = {}",path);
                String jarPath = path.substring(0, path.indexOf(".jar") + 4);
                if (UtilCommon.isLinux()) {
                    jarPath = "/" + jarPath;
                }
                localJarFile = new JarFile(jarPath);
                Enumeration<JarEntry> entries = localJarFile.entries();

                while (entries.hasMoreElements()) {
                    JarEntry jarEntry = entries.nextElement();
                    String name = jarEntry.getName();
                    if (name.indexOf("/static/file-store/dv-dtl") == -1 || name.endsWith("/static/file-store/dv-dtl/")) {
                        continue;
                    }

                    String fileName = name.substring(name.lastIndexOf("/") + 1);
                    String viewKey = fileName.substring(0, fileName.length() - 5);
                    viewKeyList.add(viewKey);
                }
            } catch (IOException e) {
                e.printStackTrace();
                log.error("getDataviewViewKeyList.error",e);
            }

        } else {
            // 文件方式启动
            File path = new File(Const.DATA_VIEW_DTL_SRC);
            File[] files = path.listFiles();
            for (File file : files) {
                String fileName = file.getName();
                String viewKey = fileName.substring(0, fileName.length() - 5);
                viewKeyList.add(viewKey);

            }
        }
        return viewKeyList;
    }

    @Override
    public Boolean isSupport(Boolean flagProject) {
        return !flagProject;
    }
}
